#!/usr/bin/env python
"""
LocoGateway by Claptrap
Handles transfer of data between LocoDKP and LocoBidder
Works with Python 2.6 and 3.1 and probably other versions,
but there seems to be a problem with parsing XML in 3.0.
"""

import sys
from xml.dom import minidom
import codecs
import os
if int(sys.version[0]) == 3:
    from tkinter import *
    import urllib.request as urllib
    from urllib.parse import urlencode
    import tkinter.messagebox as tkMessageBox
    import http.client as httplib
else:
    from Tkinter import *
    import urllib
    from urllib import urlencode
    import tkMessageBox
    import httplib

class GUIFramework(Frame):
    """This is the GUI"""
    def CreateWidgets(self):
        """Create all the widgets that we need"""
        self.urlLabel = Label(self, text="URL to LocoDKP:")
        self.urlLabel.grid(row=0, column=0, sticky=W)
        self.urlEntry = Entry(self)
        self.urlEntry.grid(row=0, column=1, sticky=E+W, columnspan=2)
        
        self.savedVariablesLabel = Label(self, text="SavedVariables filename:")
        self.savedVariablesLabel.grid(row=1, column=0, sticky=W)
        self.savedVariablesEntry = Entry(self)
        self.savedVariablesEntry.grid(row=1, column=1, sticky=E+W, columnspan=2)
        
        self.eventLabel = Label(self, text="Event Name:")
        self.eventLabel.grid(row=2, column=0, sticky=W)
        self.eventEntry = Entry(self)
        self.eventEntry.grid(row=2, column=1, sticky=E+W, columnspan=2)

        self.raidValueLabel = Label(self, text="Raid Value:")
        self.raidValueLabel.grid(row=3, column=0, sticky=W)
        self.raidValueEntry = Entry(self)
        self.raidValueEntry.grid(row=3, column=1, sticky=E+W, columnspan=2)

        self.adminUsernameLabel = Label(self, text="Admin Username:")
        self.adminUsernameLabel.grid(row=4, column=0, sticky=W)
        self.adminUsernameEntry = Entry(self)
        self.adminUsernameEntry.grid(row=4, column=1, sticky=E+W, columnspan=2)

        self.adminPasswordLabel = Label(self, text="Admin Password:")
        self.adminPasswordLabel.grid(row=5, column=0, sticky=W)
        self.adminPasswordEntry = Entry(self)
        self.adminPasswordEntry.grid(row=5, column=1, sticky=E+W, columnspan=2)

        self.mainText = Text(self, wrap=WORD, relief=SUNKEN, takefocus=0, borderwidth=1, state=NORMAL, cursor="arrow")
        self.mainText.grid(row=6, column=0, columnspan=3, sticky=N+W+S+E)

        self.btn1 = Button(self, text="Test Configuration", command=self.testConfiguration)
        self.btn1.grid(row=7, column=0)
        
        self.btn2 = Button(self, text="Download Data", command=self.downloadData)
        self.btn2.grid(row=7, column=1)

        self.btn3 = Button(self, text="Process Raid", command=self.processRaid)
        self.btn3.grid(row=7, column=2)

        self.btn4 = Button(self, text="Clear window", command=self.clearError)
        self.btn4.grid(row=8, column=0)

        self.btn5 = Button(self, text="Upload Data", command=self.uploadData)
        self.btn5.grid(row=8, column=1)

        self.btn6 = Button(self, text="Copy to Clipboard", command=self.copyToClipboard)
        self.btn6.grid(row=8, column=2)

    def uploadData(self):
        if not tkMessageBox.askokcancel('Upload?', 'This operation will upload the contents of the main textbox to LocoDKP Parse Raid Log.\nAre you sure?'):
            return
        self.saveConfig()
        remoteUrl = self.urlEntry.get().strip()
        remoteUrl = remoteUrl.replace("http://", "")
        if remoteUrl[-1] == '/':
            remoteUrl = remoteUrl[:-1]
        try:
            temp = remoteUrl.split('/', 1)
            remoteServer = temp[0]
            remoteDirectory = '/' + temp[1]
        except:
            remoteServer = remoteUrl
            remoteDirectory = ''
        adminUsername = self.adminUsernameEntry.get()
        adminPassword = self.adminPasswordEntry.get()
        if len(adminUsername) == 0 or len(adminPassword) == 0:
            self.error("Admin username and/or password not set")
            return

        if int(sys.version[0]) == 3:
            params = urlencode({'username': adminUsername,
                                'password': adminPassword})
        else:
            params = urlencode({'username': adminUsername.encode('utf-8'), 
                                'password': adminPassword.encode('utf-8')})

        headers = {"Content-type": "application/x-www-form-urlencoded",
                   "Accept": "text/plain", "User-Agent": "LocoGateway"}

        try:
            conn = httplib.HTTPConnection(remoteServer)
        except:
            self.error("HTTP connection failed")
            return

        # do login
        try:
            conn.request("POST", remoteDirectory + '/auth/login', params, headers)
            response = conn.getresponse()
            conn.close()
        except:
            self.error("HTTP request failed")
            return

        if not response.status == 302:
            self.error("Invalid server response (1)")
            return

        # parse response headers to find the cookies containing the login information
        cookieArr = list()
        for h in response.getheaders():
            if h[0].lower() == 'set-cookie':
                for cookieName in ['password', 'username']:
                    try:
                        i = h[1].index(cookieName + '=')
                        j = h[1].index(';', i)
                        cookieArr.append(h[1][i:j])
                    except:
                        pass

        if len(cookieArr) == 0:
            self.error("Invalid username/password")
            return

        headers['Cookie'] = '; '.join(cookieArr)

        # using authentication with cookie, upload the raid log
        if int(sys.version[0]) == 3:
            params = urlencode({'raidlog': self.mainText.get(1.0, END)})
        else:
            params = urlencode({'raidlog': self.mainText.get(1.0, END).encode('utf-8')})

        try:
            conn = httplib.HTTPConnection(remoteServer)
        except:
            self.error("HTTP connection failed")
            return

        try:
            conn.request("POST", remoteDirectory + "/raids/parse", params, headers)
            response = conn.getresponse()
            conn.close()
        except:
            self.error("HTTP request failed")
            return

        if not response.status == 302:
            self.error("Invalid server response (2)")
            return

        # to see what the server said about the parsed raid log, we need to access
        # the PHP session, where all messages are stored
        cookieArr = list()
        for h in response.getheaders():
            if h[0].lower() == 'set-cookie':
                for cookieName in ['password', 'username', 'PHPSESSID']:
                    try:
                        i = h[1].index(cookieName + '=')
                        j = h[1].index(';', i)
                        cookieArr.append(h[1][i:j])
                    except:
                        pass

        if len(cookieArr) == 0:
            self.error("Invalid session")
            return

        cookieString = '; '.join(cookieArr)

        try:
            conn = httplib.HTTPConnection(remoteServer)
            conn.request("GET", remoteDirectory + "/raids/parselog", '',
                        {"Cookie": cookieString, "User-Agent": "LocoGateway"})
            response = conn.getresponse()
            data = response.read()
        except:
            self.error("No data returned")
            return

        try:
            xmldoc = minidom.parseString(data)
        except:
            self.error("Unable to parse returned document")
            return

        oldContents = self.mainText.get(1.0, END)
        self.clearError()
        self.mainText.insert(END, "The server responded:\n")

        # now to parse the returned document to find the messages...
        divTags = xmldoc.getElementsByTagName('body')[0].getElementsByTagName('div')
        for divTag in divTags:
            try:
                if divTag.attributes['id'].value == 'container':
                    # find 'right' div
                    for divSubTag in divTag.getElementsByTagName('div'):
                        try:
                            if divSubTag.attributes['id'].value == 'right':
                                for divSubSubTag in divSubTag.getElementsByTagName('div'):
                                    try:
                                        for childNode in divSubSubTag.childNodes:
                                            try:
                                                data = childNode.data.strip()
                                                if len(data) > 0:
                                                    self.mainText.insert(END, data + '\n')
                                                    #wtf...
                                            except:
                                                pass
                                    except:
                                        pass
                        except:
                            pass
            except:
                pass

        self.mainText.insert(END, '\n\n' + oldContents)
        conn.close()

    def copyToClipboard(self):
        self.clipboard_clear()
        self.clipboard_append(self.mainText.get(1.0, END))

    def testConfiguration(self):
        self.saveConfig()
        self.clearError()
        remoteUrl = self.urlEntry.get().strip()
        remoteUrl = remoteUrl.replace("http://", "")
        if remoteUrl[-1] == '/':
            remoteUrl = remoteUrl[:-1]
        try:
            temp = remoteUrl.split('/', 1)
            remoteServer = temp[0]
            remoteDirectory = '/' + temp[1]
        except:
            remoteServer = remoteUrl
            remoteDirectory = ''

        adminUsername = self.adminUsernameEntry.get()
        adminPassword = self.adminPasswordEntry.get()

        self.mainText.insert(END, "Username and password set... ")
        if len(adminUsername) == 0 or len(adminPassword) == 0:
            self.mainText.insert(END, 'NO\n')
            return
        else:
            self.mainText.insert(END, 'YES\n')

        if int(sys.version[0]) == 3:
            params = urlencode({'username': adminUsername, 'password': adminPassword})
        else:
            params = urlencode({'username': adminUsername.encode('utf-8'), 'password': adminPassword.encode('utf-8')})
        headers = {"Content-type": "application/x-www-form-urlencoded",
                    "Accept": "text/plain", "User-Agent": "LocoGateway"}

        self.mainText.insert(END, "Remote server reachable... ")
        try:
            conn = httplib.HTTPConnection(remoteServer)
            self.mainText.insert(END, "YES\n")
        except:
            self.mainText.insert(END, "NO\n")
            return

        self.mainText.insert(END, "Remote path found... ")
        try:
            conn.request("POST", remoteDirectory + '/auth/login', params, headers)
            response = conn.getresponse()
            conn.close()
            if response.status == 302:
                self.mainText.insert(END, "YES\n")
            else:
                self.mainText.insert(END, "NO\n")
                return
        except:
            mainText.insert(END, "NO\n")
            return

        self.mainText.insert(END, "Username and password correct... ")
        foundCookie = False
        for h in response.getheaders():
            if h[0].lower() == 'set-cookie':
                #headers["Cookie"] = h[1].split(";", 1)[0]
                foundCookie = True
                break

        if foundCookie:
            self.mainText.insert(END, "YES\n")
        else:
            self.mainText.insert(END, "NO\n")
            return

        savedVariablesFileName = self.savedVariablesEntry.get()
        remoteUrl = self.urlEntry.get()
        self.mainText.insert(END, 'Members XML list can be downloaded... ')
        try:
            usock = urllib.urlopen('http://' + remoteServer + remoteDirectory + '/members/xml')
            self.mainText.insert(END, 'YES\n')
        except:
            self.mainText.insert(END, "NO\n")
            return

        self.mainText.insert(END, 'XML Document can be parsed... ')
        try:
            xmldoc = minidom.parse(usock)
            self.mainText.insert(END, 'YES\n')
        except:
            self.mainText.insert(END, "NO\n")
            return

        self.mainText.insert(END, 'Root node is <members>... ')
        membersElements = xmldoc.getElementsByTagName('members')
        if len(membersElements) == 1:
            self.mainText.insert(END, 'YES\n')
        else:
            self.mainText.insert(END, 'NO\n')
            return

        self.mainText.insert(END, 'SavedVariables file exists... ')
        if os.path.isfile(savedVariablesFileName):
            self.mainText.insert(END, 'YES\n')
        else:
            self.mainText.insert(END, 'NO\n')
            return

        self.mainText.insert(END, 'SavedVariables can be read in UTF-8 mode... ')
        try:
            handle = codecs.open(savedVariablesFileName, 'r', 'utf-8')
            self.mainText.insert(END, 'YES\n')
        except:
            self.mainText.insert(END, 'NO\n')
            return
        handle.close()

        self.mainText.insert(END, 'SavedVariables can be written to... ')
        if os.access(savedVariablesFileName, os.W_OK):
            self.mainText.insert(END, 'YES\n')
        else:
            self.mainText.insert(END, 'NO\n')
            return

        self.mainText.insert(END, 'Event name set... ')
        if (len(self.eventEntry.get()) > 0):
            self.mainText.insert(END, 'YES\n')
        else:
            self.mainText.insert(END, 'NO\n')
            return
        
        self.mainText.insert(END, 'Raid value is a positive integer... ')
        raidValue = self.raidValueEntry.get()
        if len(raidValue) == 0:
            self.mainText.insert(END, 'NO\n')
            return
        
        try:
            raidValue = int(raidValue)
        except:
            self.mainText.insert(END, 'NO\n')
            return

        if raidValue >= 0:
            self.mainText.insert(END, 'YES\n')
        else:
            self.mainText.insert(END, 'NO\n')
            return

        self.mainText.insert(END, '\nAll tests were successful\n')


    def downloadData(self):
        if not tkMessageBox.askokcancel('Overwrite?', 'This operation will overwrite your SavedVariables file.\nAre you sure?'):
            return
        self.saveConfig()
        self.clearError()
        remoteUrl = self.urlEntry.get().strip()
        remoteUrl = remoteUrl.replace("http://", "")
        if remoteUrl[-1] == '/':
            remoteUrl = remoteUrl[:-1]
        try:
            temp = remoteUrl.split('/', 1)
            remoteServer = temp[0]
            remoteDirectory = '/' + temp[1]
        except:
            remoteServer = remoteUrl
            remoteDirectory = ''


        savedVariablesFileName = self.savedVariablesEntry.get()
        remoteUrl = self.urlEntry.get()
        self.mainText.insert(END, 'Opening URL... ')
        try:
            usock = urllib.urlopen('http://' + remoteServer + remoteDirectory + '/members/xml')
            self.mainText.insert(END, 'Success!\n')
        except:
            self.mainText.insert(END, "Url %s could not be opened" % remoteUrl)
            return

        self.mainText.insert(END, 'Parsing XML Document... ')
        try:
            xmldoc = minidom.parse(usock)
            self.mainText.insert(END, 'Success!\n')
        except:
            self.mainText.insert(END, "XML document could not be parsed :(")
            return

        self.mainText.insert(END, 'Rebuilding DKP List... ')
        dkpList = 'LocoBidder_DKP = {\n'
        membersNode = xmldoc.getElementsByTagName('members')
        if len(membersNode) == 0:
            self.mainText.insert(END, "Invalid XML data returned - No <members> tag found")
            return

        numMembersFound = 0
        for memberNode in membersNode[0].getElementsByTagName('member'):
            try:
                memberName = memberNode.getElementsByTagName('name')[0].firstChild.data
                memberDkp = int(memberNode.getElementsByTagName('current')[0].firstChild.data)
                if len(memberName) > 0:
                    dkpList = dkpList + '    ["' + memberName + '"] = ' + str(memberDkp) + ',\n'
                    numMembersFound += 1
            except:
                pass

        dkpList = dkpList + '}'
        self.mainText.insert(END, 'Success! (' + str(numMembersFound) + ' members found)\n')

        self.mainText.insert(END, 'Opening SavedVariables in UTF-8 mode... ')
        try:
            handle = codecs.open(savedVariablesFileName, 'r', 'utf-8')
            self.mainText.insert(END, 'Success!\n')
        except:
            self.mainText.insert(END, "File %s could not be opened\n" % savedVariablesFileName)
            self.mainText.insert(END, "Attempting to create new file... ")
            try:
                handle = codecs.open(savedVariablesFileName, 'w+', 'utf-8')
                self.mainText.insert(END, 'Success\n')
            except:
                self.mainText.insert(END, 'File %s could not be created\n' % savedVariablesFileName)
                return

        self.mainText.insert(END, 'Reading SavedVariables... ')
        try:
            entireFile = handle.read()
            handle.close()
            self.mainText.insert(END, 'Success!\n')
        except:
            self.mainText.insert(END, "File %s could not be read" % savedVariablesFileName)
            return

        outString = dkpList + '\n'

        # get the config variables
        try:
            posStart = entireFile.index('LocoBidder_Config')
            posEnd = entireFile.index('}', posStart)
            outString += entireFile[posStart:posEnd+1]
        except:
            pass

        # save to file
        self.mainText.insert(END, 'Opening SavedVariables for writing in UTF-8 mode... ')
        try:
            handle = codecs.open(savedVariablesFileName, 'w', 'utf-8')
            self.mainText.insert(END, 'Success!\n')
        except:
            self.mainText.insert(END, "File %s could not be opened for writing" % savedVariablesFileName)
            return

        self.mainText.insert(END, 'Writing new DKP data to SavedVariables... ')
        try:
            handle.write(outString)
            self.mainText.insert(END, 'Success!\n')
            handle.close()
        except:
            self.mainText.insert(END, "Could not write to file %s" % savedVariablesFileName)
            return
        self.mainText.insert(END, '\nTask completed successfully!')

    def processRaid(self):
        self.saveConfig()
        self.clearError()
        savedVariablesFileName = self.savedVariablesEntry.get()
        try:
            handle = open(savedVariablesFileName, 'r')
        except:
            self.error("File %s could not be opened" % savedVariablesFileName)
            return

        try:
            entireFile = handle.read()
        except:
            self.error("File %s could not be read" % savedVariablesFileName)
            return

        # select the xml part
        try:
            posStart = entireFile.index('LocoBidder_XmlLog')
            posEnd = entireFile.index('\n', posStart)
            posStart = entireFile.index('"', posStart)
            xmlString = entireFile[posStart+1:posEnd-1].replace('\\"', '"')
        except:
            xmlString = ''
        xmlString = '<?xml version="1.0"?><auctions>' + xmlString + '</auctions>';
        try:
            xmldoc = minidom.parseString(xmlString)
            rootNode = xmldoc.firstChild
        except:
            self.error("XML document in file %s could not be parsed" % savedVariablesFileName)
            return

        self.mainText.insert(END, '=== START INFO ===\n')
        self.mainText.insert(END, self.eventEntry.get() + '\n')
        self.mainText.insert(END, self.raidValueEntry.get() + '\n')
        self.mainText.insert(END, '=== END INFO ===\n')
        self.mainText.insert(END, '=== START ROSTER ===\n')
        # select the roster part
        try:
            posStart = entireFile.index('LocoBidder_Roster')
            posEnd = entireFile.index('}', posStart)
            roster = entireFile[posStart:posEnd].split()
            for name in roster:
                if name[0] == '"':
                    self.mainText.insert(END, name[1:name.index('"', 1)] + '\n')
        except:
            pass

        self.mainText.insert(END, '=== END ROSTER ===\n')

        itemAssignments = list()
        bids = list()

        for auctionNode in rootNode.getElementsByTagName('auction'):
            cancelledNodes = auctionNode.getElementsByTagName('cancelled')
            if len(cancelledNodes) == 0: # auction was not cancelled
                # get winner
                try:
                    winnerNode = auctionNode.getElementsByTagName('adjustment')[0]
                    winnerName = winnerNode.attributes['name'].value
                    winnerAmount = -int(winnerNode.attributes['value'].value)
                    # get item name
                    itemName = auctionNode.attributes['item'].value
                    # create a new item assignment
                    itemAssignments.append([itemName, winnerName, int(winnerAmount), 1])
                    itemAssignmentId = len(itemAssignments) - 1
                    bidNodes = auctionNode.getElementsByTagName('bids')[0]
                    for bidNode in bidNodes.getElementsByTagName('bid'):
                        bidName = bidNode.attributes['name'].value
                        bidAmount = bidNode.attributes['value'].value
                        bids.append([itemAssignmentId, bidName, int(bidAmount)])
                except:
                    pass
                    
        # if the same item occurs more than once, its name must be changed by
        # appending [n], n = 1,2,3... so that it can be identified in the raid log

        countItemName = dict()
        for i in range(len(itemAssignments)):
            itemName = itemAssignments[i][0]
            try:
                countItemName[itemName] += 1
            except:
                countItemName[itemName] = 1

        for itemName in countItemName:
            if countItemName[itemName] > 1:
                sweep = 1
                for j in range(len(itemAssignments)):
                    if itemAssignments[j][0] == itemName:
                        itemAssignments[j][3] = sweep
                        sweep += 1

        adjustments = list()

        #for adjustmentNode in rootNode.getElementsByTagName('adjustment'):
        #    adjustmentName = adjustmentNode.attributes['name'].value
        #    adjustmentValue = adjustmentNode.attributes['value'].value
        #    adjustments.append([adjustmentName, int(adjustmentValue)])
        for node in rootNode.childNodes:
            if node.tagName == 'adjustment':
                adjustmentName = node.attributes['name'].value
                adjustmentValue = node.attributes['value'].value
                adjustments.append([adjustmentName, int(adjustmentValue)])
            #print adjustmentName, adjustmentValue

        # now try to eliminate paired positive/negative adjustments corresponding to
        # a misallocated item

        for i in range(len(adjustments)):
            adjustmentValue = adjustments[i][1]
            found = False
            if adjustmentValue < 0:
                for j in range(len(adjustments)):
                    if found:
                        break
                    if adjustments[j][1] == -adjustmentValue:
                        winnerName = adjustments[j][0]
                        for k in range(len(itemAssignments)):
                            if itemAssignments[k][1] == winnerName and itemAssignments[k][2] == -adjustmentValue:
                                itemAssignments[k][1] = adjustments[i][0]
                                adjustments[i][1] = 0
                                adjustments[j][1] = 0
                                found = True
                                break

        def getFormattedAssignments():
            res = ''
            for i in itemAssignments:
                res += i[1] + ';' + i[0] + ';' + str(i[2]) + '\n'
            return res

        def getFormattedAdjustments():
            res = ''
            for i in adjustments:
                if i[1] > 0:
                    res += i[0] + ';LocoBidder Adjustment;'+ str(i[1]) + '\n'
            return res

        def getFormattedBids():
            res = ''
            for i in bids:
                itemName = itemAssignments[i[0]][0]
                if countItemName[itemName] > 1:
                    itemName = itemName + '[' + str(itemAssignments[i[0]][3]) + ']'
                res += i[1] + ';' + itemName + ';' + str(i[2]) + '\n'
            return res

        self.mainText.insert(END, '=== START ITEMS ===\n')
        self.mainText.insert(END, getFormattedAssignments())
        self.mainText.insert(END, '=== END ITEMS ===\n')
        self.mainText.insert(END, '=== START BIDS ===\n')
        self.mainText.insert(END, getFormattedBids())
        self.mainText.insert(END, '=== END BIDS ===\n')
        self.mainText.insert(END, '=== START ADJUSTMENTS ===\n')
        self.mainText.insert(END, getFormattedAdjustments())
        self.mainText.insert(END, '=== END ADJUSTMENTS ===\n')

    def error(self, msg):
        self.mainText.delete(1.0, END)
        self.mainText.insert(END, "Error: %s" % msg)

    def clearError(self):
        self.mainText.delete(1.0, END)

    def saveConfig(self):
        try:
            handle = codecs.open('LocoGateway.ini', 'w', 'utf-8')
            handle.write('URL = %s\n' % self.urlEntry.get())
            handle.write('SavedVariables = %s\n' % self.savedVariablesEntry.get())
            handle.write('Event = %s\n' % self.eventEntry.get())
            handle.write('RaidValue = %s\n' % self.raidValueEntry.get())
            handle.write('AdminUsername = %s\n' % self.adminUsernameEntry.get())
            handle.write('AdminPassword = %s\n' % self.adminPasswordEntry.get())
        except:
            self.error("Could not save config to LocoGateway.ini")
            return

    def loadConfig(self):
        try:
            handle = codecs.open('LocoGateway.ini', 'r', 'utf-8')
        except:
            # no file was found, take default values instead
            self.urlEntry.insert(0, 'http://locodkp.marty.nu')
            self.savedVariablesEntry.insert(0, 'C:\\wow\\WTF\\Account\\ACCOUNTNAME\\SavedVariables\\LocoBidder.lua')
            self.eventEntry.insert(0, 'Event Name')
            self.raidValueEntry.insert(0, '10')
            self.adminUsernameEntry.insert(0, 'Username')
            self.adminPasswordEntry.insert(0, 'Password')
            return
        # parse config file
        for line in handle:
            arr = line.split('=', 1)
            try:
                key = arr[0].strip()
                value = arr[1].strip()
                if key == 'URL':
                    self.urlEntry.insert(0, value)
                elif key == 'SavedVariables':
                    self.savedVariablesEntry.insert(0, value)
                elif key == 'Event':
                    self.eventEntry.insert(0, value)
                elif key == 'RaidValue':
                    self.raidValueEntry.insert(0, value)
                elif key == 'AdminUsername':
                    self.adminUsernameEntry.insert(0, value)
                elif key == 'AdminPassword':
                    self.adminPasswordEntry.insert(0, value)
            except:
                pass

    def __init__(self,master=None):
        """Initialize yourself!"""

        """Initialise the base class"""
        Frame.__init__(self,master)

        """Set the Window Title"""
        self.master.title("LocoGateway")
        """Display the main window
        with a little bit of padding"""
        self.grid(padx=15, pady=15,sticky=N+S+E+W)
        self.CreateWidgets()

        """ Load config variables """
        self.loadConfig()

if __name__ == "__main__":
    guiFrame = GUIFramework()
    guiFrame.mainloop()

